package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	// timeOut()

	// coms:=buy(100) // 采购10套配件
	// // phones:=build(coms) // 组装10部手机
	// phones1:=build(coms)
	// phones2:=build(coms)
	// phones3:=build(coms)
	// phones:=merge(phones1,phones2,phones3)// 组装100部手机

	// packs:=pack(phones) // 打包
	// // 测试
	// for pack := range packs{
	// 	fmt.Println(pack)
	// }

	// Futures模式
	vegetablesCh := washVegetables()
	waterCh := boilWater()
	fmt.Println("已经安排洗菜和烧水了，看会电视！")
	time.Sleep(2 * time.Second)

	fmt.Println("要做火锅了，看看菜和水都好了吗？")
	vegetables := <-vegetablesCh
	water := <-waterCh
	fmt.Println("准备好了，可以做火锅了：", vegetables, water)
}

// select timeout模式
func timeOut() {
	result := make(chan string)
	go func() {
		// 模拟网络访问
		time.Sleep(8 * time.Second)
		result <- "服务端结果"
	}()
	select {
	case v := <-result:
		fmt.Println(v)
	case <-time.After(5 * time.Second):
		fmt.Println("网络访问超时了！")
	}
}

// Pipeline 模式 流水线模式 1 采购
func buy(n int) <-chan string {
	out := make(chan string)
	go func() {
		defer close(out)
		for i := 1; i <= n; i++ {
			out <- fmt.Sprint("配件", i)
		}
	}()
	return out
}

// 2组装
func build(in <-chan string) <-chan string {
	out := make(chan string)
	go func() {
		defer close(out)
		for c := range in {
			out <- "组装（" + c + ")"
		}
	}()
	return out
}

// 扇入函数
func merge(ins ...<-chan string) <-chan string {
	var wg sync.WaitGroup
	out := make(chan string)
	// channel 中的数据发送到out中
	p := func(in <-chan string) {
		defer wg.Done()
		for c := range in {
			out <- c
		}
	}
	wg.Add(len(ins))
	// 扇入 启动多个goroutine用于处于多个channnel中的数据
	for _, cs := range ins {
		go p(cs)
	}
	// 等待数据处理完 关闭输出out
	go func() {
		wg.Wait()
		close(out)
	}()
	return out
}

// 打包
func pack(in <-chan string) <-chan string {
	out := make(chan string)
	go func() {
		defer close(out)
		for c := range in {
			out <- "打包(" + c + ")"
		}
	}()
	return out
}

/*Futures模式*/
// 洗菜
func washVegetables() <-chan string {
	vegetables := make(chan string)
	go func() {
		time.Sleep(5 * time.Second)
		vegetables <- "洗好的菜"
	}()
	return vegetables
}

// 烧水
func boilWater() <-chan string {
	water := make(chan string)
	go func() {
		time.Sleep(5 * time.Second)
		water <- "烧开的水"
	}()
	return water
}
